#include <iostream>
#include <string>
using namespace std;

_NODISCARD _Ret_notnull_ _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR
void* __CRTDECL operator new(size_t _Size)
// void* operator new(size_t _Size)
{
    void* p = malloc(_Size);
    if (p == nullptr) {
        throw bad_alloc{};
    }
    printf("::operator new(%zu), p=%p\n", _Size, p);
    return p;
}

void operator delete(void * p)
{
    printf("::operator delete(%p)\n", p);
    free(p);
}

_NODISCARD _Ret_notnull_ _Post_writable_byte_size_(size) _VCRT_ALLOCATOR
// void* __CRTDECL operator new[](
void* __CRTDECL operator new[](size_t size)
{
    void* p = malloc(size);
    if (p == nullptr) {
        throw bad_alloc{};
    }
    printf("::operator new[](%zu), p=%p\n", size, p);
    return p;
}

void operator delete[](void * p)
{
    printf("::operator delete[](%p)\n", p);
    free(p);
}

struct test
{
    static int id;
    const int _id = ++id;
    test() {printf("test(%d), sizeof(*this)=%zu\n", _id, sizeof(*this));}
    ~test() {printf("~test(%d)\n", _id);}
    void * operator new(size_t size) {
        void* p = ::operator new(size);//malloc(size);
        printf("operator test::new(%zu), p=%p\n", size, p);
        return p;
    }
    void operator delete(void * p)
    {
        printf("operator test::delete(%p)\n", p);
        //free(p);
        ::operator delete(p);
    }
    void * operator new[](size_t size) {
        void* p = ::operator new[](size);//malloc(size);
        printf("operator test::new[](%zu), p=%p\n", size, p);
        return p;
    }
    void operator delete[](void * p)
    {
        printf("operator test::delete[](%p)\n", p);
        //free(p);
        ::operator delete[](p);
    }
};
int test::id = 0;

struct separator
{
    separator(const char* title) : _title(title)
    {
        printf(">>>> begin: %s >>>>\n", _title);
    }
    ~separator()
    {
        printf("<<<<< end: %s <<<<<\n\n", _title);
    }
    const char * _title;
};

int main()
{
    {
        separator s("global");

        string hello{"hello"};
        string world{"world"};
    }

    {
        separator s("class");

        test* t1 = new test;
        test* t2 = new test;

        delete t2;
        delete t1;
    }

    {
        separator s("global array");
        printf("sizeof(string) = %zu\n", sizeof(string));
        string* str_arr = new string[4];
        int size = *((int*)(reinterpret_cast<char*>(str_arr) - 8));
        printf("size = %d\n", size);
        delete[] str_arr;
    }

    {
        separator s("class array");

        test* test_arr = new test[10];
        //printf("sizeof(void*) = %zu\n", sizeof(void*));
        int size = *((int*)(reinterpret_cast<char*>(test_arr) - 8));
        printf("size = %d\n", size);
        delete [] test_arr;
    }

    return 0;
}
